package reply

import (
	"context"
	"fmt"

	"mall/service/backend/api/internal/lib/memberrank"
	"mall/service/backend/api/internal/logic/forum/util"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/api/internal/utils/parse"
	"mall/service/backend/common/i18n"
	"mall/service/backend/common/utils/pointy"
	"mall/service/forum/rpc/forumclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetPostListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetPostListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPostListLogic {
	return &GetPostListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetPostListLogic) GetPostList(req *types.ForumPostListReq) (*types.ForumPostListResp, error) {
	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	var status uint32
	if req.Status != nil {
		status = *req.Status + 1
	}

	orderBys := util.ParseSorterNew(req.Sorter)
	filterBys := util.ParseFilterNew(req.Filter, req.Type)
	data, err := l.svcCtx.ForumRpc.BackendGetReplyList(l.ctx, &forumclient.BackendPostListReq{
		Page:     page,
		PageSize: pageSize,
		ForumId:  req.ForumId,
		TopicId:  req.TopicId,
		AuthorId: req.AuthorId,
		Ids:      req.PostIds,
		Status:   &status,
		Sticky:   req.Sticky,
		OrderBy:  orderBys,
		FilterBy: filterBys,
	})
	if err != nil {
		return nil, err
	}

	resp := &types.ForumPostListResp{
		BaseDataInfo: types.BaseDataInfo{
			Success: true,
			Msg:     l.svcCtx.Trans.Trans(l.ctx, i18n.Success),
		},
		Data: types.ForumPostListInfo{
			BaseListInfo: types.BaseListInfo{
				Current:  page,
				PageSize: pageSize,
				Total:    data.GetTotal(),
			},
		},
	}

	if len(data.List) > 0 {
		memberRankMap := l.getMemberRankMap()

		for _, v := range data.List {
			var media []*types.MediaInfo
			if len(v.Media) > 0 {
				for _, m := range v.Media {
					var url string
					if m.Url != nil && len(*m.Url) > 0 {
						url = *m.Url
					}
					if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
						url = *m.Uri
					}
					media = append(media, &types.MediaInfo{
						Uid:       m.Uid,
						Id:        m.Id,
						Url:       pointy.GetPointer(url),
						Thumbnail: m.Thumbnail,
						AltText:   m.AltText,
						MetaData:  m.Meta,
						Order:     m.Order,
					})
				}
			}

			var topic *types.ForumTopicInfo
			if v.Topic != nil {
				tv := v.Topic
				var author *types.ForumAuthorInfo
				var levelName *string
				var levelUrl *string
				if tv.Author != nil && memberRankMap != nil && tv.Author.Level != nil && *tv.Author.Level > 0 {
					if memberRank, ok := memberRankMap[*tv.Author.Level]; ok {
						levelName = memberRank.Name
						levelUrl = memberRank.PicUrl
					}
				}
				if tv.Author != nil && tv.Author.Name != nil {
					var anonymous *bool
					if tv.Author.Anonymous != nil {
						anonymous = pointy.GetPointer(*tv.Author.Anonymous > 0)
					}
					author = &types.ForumAuthorInfo{
						Id:        tv.Author.Id,
						Name:      tv.Author.Name,
						Avatar:    tv.Author.Avatar,
						Ip:        tv.Author.Ip,
						Level:     tv.Author.Level,
						Anonymous: anonymous,
						LevelName: levelName,
						LevelUrl:  levelUrl,
					}
				}
				var statusText *string
				if tv.Status != nil {
					statusText = pointy.GetPointer(util.GetStatusText(int32(*tv.Status)))
				}
				topic = &types.ForumTopicInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id:        tv.Id,
						CreatedAt: tv.CreatedAt,
						UpdatedAt: tv.UpdatedAt,
					},
					ForumId:      tv.ForumId,
					AuthorId:     tv.AuthorId,
					Title:        tv.Title,
					Slug:         tv.Slug,
					Status:       tv.Status,
					StatusText:   statusText,
					Sticky:       tv.Sticky,
					ReplyCount:   tv.PostCount,
					CommentCount: tv.CommentCount,
					Author:       author,
				}
			}

			var author *types.ForumAuthorInfo
			var levelName *string
			var levelUrl *string
			if v.Author != nil && memberRankMap != nil && v.Author.Level != nil && *v.Author.Level > 0 {
				if memberRank, ok := memberRankMap[*v.Author.Level]; ok {
					levelName = memberRank.Name
					levelUrl = memberRank.PicUrl
				}
			}
			if v.Author != nil && v.Author.Name != nil {
				var anonymous *bool
				if v.Author.Anonymous != nil {
					anonymous = pointy.GetPointer(*v.Author.Anonymous > 0)
				}
				author = &types.ForumAuthorInfo{
					Id:        v.Author.Id,
					Name:      v.Author.Name,
					Avatar:    v.Author.Avatar,
					Ip:        v.Author.Ip,
					Level:     v.Author.Level,
					Anonymous: anonymous,
					LevelName: levelName,
					LevelUrl:  levelUrl,
				}
			}

			var statusText *string
			if v.Status != nil {
				statusText = pointy.GetPointer(util.GetStatusText(int32(*v.Status)))
			}

			option := util.GetOptionByStatusAndType(v.Status, v.Sticky, v.ForumId)
			resp.Data.List = append(resp.Data.List, &types.ForumPostInfo{
				BaseIDInfo: types.BaseIDInfo{
					Id:         v.Id,
					CreatedAt:  v.CreatedAt,
					UpdatedAt:  v.UpdatedAt,
					DeletedAt:  v.DeletedAt,
					CanAccept:  option.CanAccept,
					CanReject:  option.CanReject,
					CanRemove:  option.CanRemove,
					CanRestore: option.CanRestore,
				},
				ForumId:        v.ForumId,
				ContentHtml:    v.ContentHtml,
				AuthorId:       v.AuthorId,
				TopicId:        v.TopicId,
				Media:          media,
				Status:         v.Status,
				StatusText:     statusText,
				Sticky:         v.Sticky,
				CommentStatus:  v.CommentStatus,
				CommentCount:   v.CommentCount,
				PhotoCount:     v.PhotoCount,
				Author:         author,
				Topic:          topic,
				CanStick:       option.CanStick,
				CanUnstick:     option.CanUnstick,
				CanForceDelete: option.CanForceDelete,
			})
		}
	}

	return resp, nil
}

func (l *GetPostListLogic) getMemberRankMap() map[uint32]*types.MemberRankInfo {
	memberRank := memberrank.NewMemberRank(l.ctx, l.svcCtx)
	memberRankList, err := memberRank.List()
	if err != nil {
		logrus.Info(fmt.Sprintf("GetPostList getMemberRankMap err: %+v", err))
		return nil
	}

	if len(memberRankList) > 0 {
		resp := make(map[uint32]*types.MemberRankInfo)
		for _, v := range memberRankList {
			if v.Id != nil && *v.Id > 0 {
				resp[uint32(*v.Id)] = v
			}
		}

		return resp
	}

	return nil
}
